這一節我們來用前幾篇文章學到的一切來做個小範例吧!不知道大家在學網頁時,第一個嘗試的是什麼?當然這邊指的是除了Hello world!
之外的XD,小弟我啊!遙想起三年前某個晚上下班時,看到朋友做的留言版,就莫名走上IT這條路了,所以今天也來用react
做個留言板吧!
不過雖說是要做個留言板,但不會整個都做啦!簡單把渲染出留言的部分做出來,然後可以使用搜尋匡查詢出留言者就好!那讓我們看看怎麼做吧!
哈哈!這個階段其實是我自己想的,不過這卻是在動手之前相當重要的事情,畢竟要好好思考怎麼做,才不會做白工,所以假設我們拿到的畫面像這樣子:
嗚嗚,不要笑,這只是個簡單小範例對吧!
當我們拿到畫面時,就要把他切成一塊一塊的組件,然後用組合的方式把它合起來,而一個組件盡量只有一個功能,如果有兩個,那就把他切成兩個組件處理!這個叫做單一功能原則,所以根據原則判斷,可以把上方的留言畫面切成幾個組件處理:
讓我們從最小的組件看到最大:
根據上方的結論,我們就可以先寫下這四個組件的class
:
class Message extends React.Component{
}
class MessageBlock extends React.Component{
}
class SearchBlock extends React.Component{
}
class MessageForm extends React.Component{
}
//最後只輸出MessageForm
ReactDOM.render(<MessageForm />, document.getElementById('root'))
在開始的第一步,我們應該都會先取得後端傳過來的資料,假設他長這樣子:
//訊息資料
let data = [{id:'1',name:'神Q',message:'嗨!大家好啊!'},
{id:'2',name:'小馬',message:'早安啊!昨天有沒有好好發文?'},
{id:'3',name:'王子',message:'ㄛ!別說了,那真的超級累!'},
{id:'4',name:'神Q',message:'哈哈哈!加油啦!再一下就結束了!'},
{id:'5',name:'王子',message:'結束後我一定要爆睡一頓!'},]
那我們應該會透過props
將這個data
資料傳進MessageForm
中,因為我們最後也只輸出這個組件,所以ReactDOM.render
會變成:
//把訊息資料傳進MessageForm中
ReactDOM.render(<MessageForm messageData={data} />
, document.getElementById('root'))
傳進去後就可以先處理輸出訊息的部分,搜尋放最後再做,畢竟沒有看到留言也沒辦法測試搜尋正不正確:
class MessageForm extends React.Component{
render(){
return(
<div>
{/*透過props的單向資料流,再將訊息傳入MessageBlock中處理*/}
<MessageBlock messageData={this.props.messageData} />
</div>
)
}
}
既然資料已經傳到MessageBlock
中了,接著就要把每筆的留言資料用Message
組件輸出了,因為只是把陣列裡面的資料一筆一筆放到Message
,所以可以用迴圈處理:
class Message extends React.Component{
render(){
//這邊做一些簡單的樣式,不然留言會全部擠在一起
let divStyle={marginBottom:20}
let messageStyle={marginLeft:20}
return(
<div style={divStyle}>
{/*把每筆傳進來的留言資料都放好後回傳*/}
<div>{this.props.name}對大家說:</div>
<div style={messageStyle}>{this.props.message}</div>
</div>
)
}
}
class MessageBlock extends React.Component{
render(){
//用map迴圈把每筆留言的資料都用props傳進Message組件放好,再指定給message
let message = this.props.messageData.map((item)=>{
return <Message key={item.id} name={item.name} message={item.message} />
})
return (
<div>
{/*回傳放完留言資料的message變數*/}
{message}
</div>
)
}
}
從上方的例子中可以看到,從最外層的MessageForm
組件到最裡面的Message
都是利用props
來傳輸資料,組件內的資料是從外面單向流到裡面,這樣可以確保資料是不會在不同組件中被異動且正確的!
經過上方的努力,畫面上已經可以看見留言資料了:
既然我們已經有資料了,就可以來處理查詢這一塊,查詢的組件畫面很簡單,只需要一段文字和一個輸入框:
class SearchBlock extends React.Component{
render(){
return(
<div>
<span>搜尋留言人:</span>
<input type="text" />
</div>
)
}
}
畫面處理好後,把SearchBlock
加進MessageForm
中,並在訊息間插個分隔線的標籤<hr>
:
class MessageForm extends React.Component{
render(){
return(
<div>
<SearchBlock />
<hr/>
{/*透過props的單向資料流,再將訊息傳入MessageBlock中處理*/}
<MessageBlock messageData={this.props.messageData} />
</div>
)
}
}
目前為止已經將畫面都做出來了:
但這並不是我們的目標對吧!現在那個輸入框就像裝飾用的一樣,根本沒有任何功能,再下一步之前先試想一下,當我們在SearchBlock
內的輸入框輸入資料時,要根據我們輸入的值來篩選MessageBlock
中的訊息內容,所以這兩個組件間同時間需要一個相同值,有沒有很熟悉?想想兩天前我們做了什麼...
沒錯!就是將共同的值放到最近的共同父組件的state
中!而他們的共同父組件就是MessageForm
!改寫時間又到了,增加constructor
吧:
class MessageForm extends React.Component{
constructor(props){
super(props)
//增加了state.name用來放篩選留言者的值
this.state = ({name:''})
//照慣例也新增個changeState用來在使用者輸入值的時候觸發事件,改變state
this.changeState = this.changeState.bind(this)
}
//更新使用者目前輸入的值到state中
changeState(event){
this.setState({name:event.target.value})
}
render(){
return(
<div>
{/*把state中的name和執行的事件都用props給SearchBlock*/}
<SearchBlock searchName={this.state.name}
changeState={this.changeState} />
<hr />
{/*這裡也要傳入state的name用來篩選留言*/}
<MessageBlock messageData={this.props.messageData}
searchName={this.state.name} />
</div>
)
}
先回到剛剛的SearchBlock
中,把傳進來的資料和事件安置好:
class SearchBlock extends React.Component{
render(){
return(
<div>
<span>搜尋留言人:</span>
{/*這裡將MessageForm的state.name給輸入框的value,
並設定onChange再值改變的時候可以執行changeState事件*/}
<input type="text"
value={this.props.searchName}
onChange={this.props.changeState} />
</div>
)
}
}
最後要處理的地方是輸出訊息的區塊,記得我們是在哪一個組件中使用Message
的嗎?就是在MessageBlock
的迴圈內,這裡的寫法很單純,只需要判斷每個訊息的留言人裡面是否含有props.searchName
的值,如果有就跑Message
,沒有就不做處理:
class MessageBlock extends React.Component{
render(){
let message = this.props.messageData.map((item)=>{
//在這裡用if判斷留言者item.name中是否含有this.props.searchName的值,如果有就執行,沒有就不動作
if(item.name.indexOf(this.props.searchName)!=-1)
return <Message key={item.id} name={item.name} message={item.message} />
})
return (
<div>
{message}
</div>
)
}
}
來到這裡的各位可以給自己一點鼓勵!因為我們完成了!結果如下:
他只會依照輸入框中的值去匯出符合的留言資料!以下附上GitHub和GitPage:
GitHub連結
GitPage連結
實際做起來不難吧!只是把前幾篇的所有文章都做個大整理XD,從class
、props
、state
、if
、for
、事件觸發,全部都做到了XD,有沒有覺得不知不覺也學到不少了,哈哈哈!可以帶著這份成就感明天跟著我繼續學習!
最後感謝各位大大的觀看,如果文章中有任何錯誤會解釋不清楚的地方,還麻煩留言告訴我,小弟會盡快修正文章內容和改進的,謝謝大家
參考文章: